/*
 * Università degli Studi di Trento
 * Facoltà di Scienze MM.FF.NN.
 * Corso di Laurea Triennale in Informatica
 * A.A. 2011/2012
 * Progetto per il corso di Sistemi Operativi 1
 * Progetto 3: 
 * Autori:
 * Bertoldi Lorenzo 155863
 * Cattin Cosso Manuel 146607
 * Parrello Nicola 145610
 */

/********************************************************************************
  Questa file contiene implementazione dei metodi della lista dei thread
  ad essa collegati.
********************************************************************************/


#include "threadFiglio.h"
#include "listaThread.h"
#include "definizioni.h"


/*
 * Costruttore:
 * Alloca lo spazio per la struttura di accesso e istanzia le variabili
 * Restituisce un puntatore nullo.
*/
pListaThread ListaThread_create(){
    pListaThread lt= new(ListaThread);
    lt->inizio=NULL;
    lt->fine=NULL;
    lt->dim=0;
    lt->attivi=0;
    return lt;
}

/*
 * insert :
 * Inserisce il puntatore nella lista, se la lista non esiste ne crea una
*/
void ListaThread_insert(pListaThread lt, pThreadFiglio thread){
    if(lt==NULL){
        lt=new(ListaThread);
        lt->inizio=NULL;
        lt->fine=NULL;
        lt->dim=1;
        pNodoListaThread nodo=new(NodoListaThread);
        nodo->next=NULL;
        nodo->thread=thread;
        lt->inizio=nodo;
        lt->fine=nodo;
    }else if(lt->inizio==NULL){
        pNodoListaThread nodo=new(NodoListaThread);
        nodo->next=NULL;
        nodo->thread=thread;
        lt->inizio=nodo;
        lt->fine=nodo;
        lt->dim++;
    }else {
        pNodoListaThread nodo=new(NodoListaThread);
        nodo->next=NULL;
        nodo->thread=thread;
        lt->fine->next=nodo;
        lt->fine=nodo;
        lt->dim++;
    }
    if(thread->state==RUN){
        lt->attivi++;
    }
}

/*
 * find:
 * Ritorna il thread alla posizione n
*/
pThreadFiglio ListaThread_find(pListaThread lt, int numDaCerc){
    if((lt==NULL)||(lt->dim==0)||(numDaCerc>=lt->dim)){
        printf("Errore il thread ha un numero esterno all'ampiezza della lista\n");
        return NULL;
    }else{
        pNodoListaThread nodo=lt->inizio;
        pNodoListaThread prec=NULL;
        while(numDaCerc>0){
            prec=nodo;
            nodo=nodo->next;
            numDaCerc--;
        }
        return nodo->thread;
    }
}

/*
 * ricompattaLista:
 * Rimuove i thread con stato FINISH dalla lista
 * return: il numero di nodi rimossi
*/
int ListaThread_ricompattaLista(pListaThread lt){
    if((lt==NULL)||(lt->dim==0)){
        return -1;
    }else{
        int rimossi=0;
        pNodoListaThread nodo;
        //Rimuovo all'inizio della lista
        while((lt->inizio!=NULL)&&(lt->inizio->thread->state==FINISH)){
            nodo=lt->inizio;
            //E' il primo
            if(lt->inizio==lt->fine){
                lt->inizio=NULL;
                lt->fine=NULL;
            }else{
                //Se ci sono altri elementi passo all'elemento successivo
                lt->inizio=lt->inizio->next;
            }
            rimossi++;
            lt->dim--;
            lt->attivi--;
            ThreadFiglio_destroy(nodo->thread);
            delete(nodo);
        }
        //Rimuovo in mezzo alla lista
        if(lt->inizio!=NULL){
            pNodoListaThread prec=lt->inizio; 
            nodo=prec->next;
            while(nodo!=NULL){
                if(nodo->thread->state==FINISH){
                    rimossi++;
                    lt->dim--;
                    lt->attivi--;
                    prec->next=nodo->next;
                    if(lt->fine==nodo){
                        //Se elimino l'ultimo elemento
                        lt->fine=prec;
                    }
                    ThreadFiglio_destroy(nodo->thread);
                    delete(nodo);
                }else{
                    prec=nodo;
                }
                nodo=prec->next;
            }
        }        
        return rimossi;
    }
}

/*
 * distruttore:
 * Rimuove tutti gli elementi dalla lista 
*/
void ListaThread_destroy(pListaThread lt){
    pNodoListaThread nodo=lt->inizio;
    pNodoListaThread tmp;
    while(nodo!=NULL){
        tmp=nodo->next;
        ThreadFiglio_destroy(nodo->thread);
        delete(nodo);
        nodo=tmp;
    }
    delete(lt);
}


